;; Copyright © 2021, 2022, 2023 Joshua Branson <jbranso@dismail.de>
;;
;; This is an operating system configuration template for a "basic desktop" setup using the sway window manager
;; I am trying to make my computer a LIFE computer.
;; This means that it would NOT run any graphical program.
;;

(add-to-load-path (dirname (current-filename)))

(use-modules (gnu)
             (guix)
             ;; (guile-web)
             (srfi srfi-1)
             ;; (secret nginx)
             ;; (secret hostfile)
             ;;(guixrus packages wayland-xyz)
             )

(use-service-modules avahi
                     databases
                     ;; base
                     desktop ;for fontconfig-file-service
                     dbus
                     dict
                     linux
                     mail
                     mcron
                     networking
                     sound
                     sysctl
                     web)

(use-package-modules base idutils ;gnome
                     package-management)

;; (define mbsync-every-5-minutes
;;   ;; Every 5 minutes
;;   ;; The job's action is a shell command.
;;   #~(job "*/5 * * * *" "mbsync -c /home/joshua/.mbsyncrc -a"
;;          #:user "joshua"))

(define %15-minutes
  (* 15 60))

(define updatedb-job
  ;; Run 'updatedb' at 11AM every day.  Here we write the
  ;; job's action as a Scheme procedure.
  #~(job '(next-hour '(11))
         (lambda ()
           (execl (string-append #$findutils "/bin/updatedb") "updatedb"
                  "--prunepaths=/tmp /var/tmp /gnu/store")) "updatedb"))

(define idutils-job
  ;; Update the index database as user "charlie" at 12:15PM
  ;; and 19:15PM.  This runs from the user's home directory.
  #~(job '(next-minute-from (next-hour '(12 19))
                            '(15))
         (string-append #$idutils "/bin/mkid src")
         #:user "charlie"))

;;I do not use zile.  So no need to have it.
(define %my-base-packages
  (remove (lambda (package
                    )
            (member (package-name package)
                    (list "zile"))) %base-packages))

;; (define (auto-login-to-tty config tty user)
;;   (if (string=? tty
;;                 (mingetty-configuration-tty config))
;;       (mingetty-configuration (inherit config)
;;                               (auto-login user)) config))

;;(define %current-directory "/home/joshua/prog/gnu/guix/guix-config/")

(define %current-directory
  (dirname (current-filename)))

(define* (path-join #:rest args)
  (string-join args "/"))

(define (config-file file)
  (local-file (path-join %conf-dir file)))

(define %my-base-services
  (modify-services %base-services
    ;; elogind-service
    ;; I customize my pulseaudio-service down below,
    ;; so I need to remove it here.
    ;;
    ;; I would prefer to instead of copying the file, just modify the default script
    ;; certainly guile can take the default script, change a line, and pass back
    ;; the modified file.
    ;;
    ;; This bit of code lets me change the input and out speakers and microphones for my laptop
    ;; so that I can use the nice headset that I have.
    
    (delete agetty-service-type)
    (delete mingetty-service-type)
    (delete mingetty-service-type)
    (delete mingetty-service-type)
    (delete mingetty-service-type)
    (delete mingetty-service-type)
    (delete mingetty-service-type)

    ;; (mingetty-service-type config =>
    ;; (auto-login-to-tty config "tty2" "joshua"))
    ;; (mingetty-service-type config =>
    ;; (auto-login-to-tty config "tty3" "joshua"))

    (guix-service-type
     config =>
     (guix-configuration (inherit config)
                         (discover? #t)
                         (max-silent-time %15-minutes)
                         (substitute-urls
                          (append (list
                                   ;; this substitute can be slow sometimes.
                                   ;;"https://bordeaux-us-east-mirror.cbaines.net/"
                                   "https://guix.tobias.gr"
                                   "https://substitutes.nonguix.org")
                                  %default-substitute-urls))
                         (authorized-keys
                          (append
                           (list
                            (plain-file
                             "substitutes.nonguix.org"
                             "(public-key\n (ecc\n  (curve Ed25519)\n  (q #C1FD53E5D4CE971933EC50C9F307AE2171A2D3B52C804642A7A35F84F3A4EA98#)\n  )\n )")
                            (plain-file
                             "guix.tobias.gr"
                             "(public-key\n (ecc\n  (curve Ed25519)\n  (q #E21911E159DB6D031A763509A255B054360A4A96F5668CBBAC48052E67D274D3#)\n  )\n )\n")
                            (plain-file
                             "bordeaux.guix.gnu.org.signing.key"
                             "\n(public-key\n (ecc\n  (curve Ed25519)\n  (q #7D602902D3A2DBB83F8A0FB98602A754C5493B0B778C8D1DD4E0F41DE14DE34F#)\n  )\n )"))))
                         ;; TODO would this work?  it would be like adding --fallback by default.
                         ;; (fallback #t)
                         ;; (timeout %15-minutes)
                         ;; ok specifying the --fallback breaks the daemon.  weird.
                         ;; (extra-options '("--fallback"))
                         ;; I have two CPUs...
                         (extra-options '("--max-jobs=2"))))

    ;; <dstolfa> jab`: you can also check `sysctl kernel.unprivileged_bpf_disabled`,
    ;; if that returns 1, that means it only works with root
    ;; https://vez.mrsk.me/linux-hardening.html#kern
    (sysctl-service-type config =>
                         (sysctl-configuration
                          (settings
                           (append
                            '(("vm.swappiness" . "30")
                              ;; disable ipv6
                              ("net.ipv6.conf.all.disable_ipv6" . "1")
                              ("net.ipv6.conf.all.disable_policy" . "1")
                              ("net.ipv6.conf.default.disable_ipv6" . "1")
                              ("net.ipv6.conf.default.disable_policy" . "1")
                              ("net.ipv6.conf.enp0s10.disable_ipv6" . "1")
                              ("net.ipv6.conf.enp0s10.disable_policy" . "1")
                              ("net.ipv6.conf.lo.disable_ipv6" . "1")
                              ("net.ipv6.conf.lo.disable_policy" . "1")
                              ;; disable ebpf in kernel virtual machine for unprivledged users
                              ("sysctl kernel.unprivileged_bpf_disabled" . "1")
                              ("spec_store_bypass_disable" . "on")
                              ("spectre_v2" . "on")
                              ("lld_flush" . "on")
                              ;; need to enable apparmor for this...
                              ;; ("lockdown" . "confidentiality")
                              ("init_on_alloc" . "1")
                              ("init_on_free" . "1")
                              ("page_alloc.shuffle" . "1")
                              ;; ("slab_nomerge")
                              ("vsyscall" . "1")
                              ;; ("slub_debug" . "F")
                              ("randomize_kstack_offset" . "1")
                              ;; disable re-leading a running kernel
                              ("kernel.kexec_load_disabled" . "1")
                              ;; restrict kernel pointers
                              ("kernel.kptr_restrict" . "2")
                              ;; unprivledegd users cannot get perf events
                              ("kernel.perf_event_paranoid" . "3")
                              ;; only privledged users can use bpf
                              ("net.core.bpf_jit_harden" . "2")
                              ("kernel.unprivleged_bpf" . "1")
                              ;; prevest some proofing attacks
                              ("net.ipv4.conf.all.rp_filter" . "1")
                              ("net.ipv4.conf.default.rp_filter" . "1")
                              ;; disable icmp redirects and
                              ;; RFC1620 shared media redirects
                              ("net.ipv4.conf.all.accept_redirects" . "0")
                              ("net.ipv4.conf.all.secure_redirects" . "0")
                              ("net.ipv4.conf.all.send_redirects" . "0")
                              ("net.ipv4.conf.all.shared_media" . "0")
                              ("net.ipv4.conf.default.accept_redirects" . "0")
                              ("net.ipv4.conf.default.secure_redirects" . "0")
                              ("net.ipv4.conf.default.send_redirects" . "0")
                              ("net.ipv4.conf.default.shared_media" . "0")
                              ("net.ipv6.conf.all.accept_redirects" . "0")
                              ("net.ipv6.conf.default.accept_redirects" . "0")
                              ;; disallow source-routed packets
                              ("net.ipv4.conf.all.accept_source_route" . "0")
                              ("net.ipv4.conf.default.accept_source_route" . "0")
                              ("net.ipv6.conf.all.accept_source_route" . "0")
                              ("net.ipv6.conf.default.accept_source_route" . "0")
                              ;; disable pings sent to a broadcast address
                              ("net.ipv4.icmp_echo_ignore_broadcasts" . "1")
                              ;; disable bogus icmp error responses
                              ("net.ipv4.icmp_ignore_bogus_error_responses" . "1")

                              ;; protect against time-wait assassination hazards in tcp
                              ("net.ipv4.tcp_rfc1337" . "1")

                              ("net.ipv4.tcp_sack" . "0")
                              ("net.ipv4.tcp_dsack" . "0")

                              ("net.ipv4.tcp_timestamps" . "0")
                              ("vm.mmap_rnd_bits" . "32")
                              ("vm.mmap_rnd_compat_bits" . "16")
                              ("net.ipv4.icmp_echo_ignore_all" . "1"))
                                   %default-sysctl-settings))))))

(operating-system
  (host-name "dobby")
  ;; (hosts-file
  ;; (plain-file "hosts"
  ;; (string-append
  ;; "127.0.0.1 localhost dobby\n"
  ;; "127.0.0.1 localhost dobby\n"
  ;; "127.0.0.1 guile.web.server.com guile.web.com www.date.com date.com\n"
  ;; "127.0.0.1 local.gnucode.me\n"
  ;; "127.0.0.1 local.the-nx.com\n"
  ;; ;; this is my guix linode server
  ;; "45.56.66.20 locke-lamora lamora locke\n"
  ;; "127.0.0.1 local.propernaming.org"
  ;; ;;%other-hosts-file-lines
  ;; "::1 localhost dobby"
  ;; )))
  (timezone "America/Indiana/Indianapolis")
  (locale "en_US.utf8")
  ;; (initrd-modules (list "e1000e" "i915" %base-initrd-modules))
  ;; when I reboot, does cat /proc/cmdline still show that I blacklisted:
  ;; modprobe.blacklist=usbmouse,usbkbd  ?
  (kernel-arguments (append (list "modprobe.blacklist=pcspkr"
                                  ;; use the next line when you need to update
                                  ;; the libreboot firmware
                                  ;;"iomem=relaxed"
                                  )
                            %default-kernel-arguments))
  (keyboard-layout (keyboard-layout "us"
                                    "dvorak"
                                    #:model "thinkpad"
                                    #:options '("ctrl:swapcaps")))
  ;; Boot in "legacy" BIOS mode, assuming /dev/sdX is the
  ;; target hard disk, and "my-root" is the label of the target
  ;; root file system.
  (bootloader (bootloader-configuration
                (bootloader grub-bootloader)
                (keyboard-layout keyboard-layout)
                (targets (list "/dev/sda"))))
  (mapped-devices (list (mapped-device
                          (source (uuid "d78d224d-4b5a-416e-afef-3ce77c4bd5ac"))
                          (target "cryptroot")
                          (type luks-device-mapping))))
  (file-systems (cons* (file-system
                         (device "tmpfs")
                         (mount-point "/home/joshua/tmp")
                         (type "tmpfs")
                         (check? #f)
                         (flags '(no-suid no-dev))
                         (options "size=50%") ;TODO: make size configurable
                         (create-mount-point? #t))
                       (file-system
                         (mount-point "/")
                         (device "/dev/mapper/cryptroot")
                         (type "ext4")
                         (dependencies mapped-devices))

                       ;; (file-system
                       ;; (mount-point "/mnt/debian")
                       ;; (device "/dev/sda3")
                       ;; (type "ext4"))
                       %base-file-systems))

  (users (cons* (user-account
                  (name "joshua")
                  (comment "Joshua Branson")
                  (group "users")
                  (home-directory "/home/joshua")
                  (supplementary-groups '("audio" "kvm" "netdev" "wheel"
                                          "seat"))) %base-user-accounts))

  ;; Globally-installed packages.
  (packages (append (map specification->package
                         '("nss-certs")) %my-base-packages))

  (services
   (cons* (service dicod-service-type)

          ;; The global fontconfig cache directory can sometimes contain
          ;; stale entries, possibly referencing fonts that have been GC'd,
          ;; so mount it read-only.
          fontconfig-file-system-service

          (service dbus-root-service-type)
          (service dhcp-client-service-type)
          ;; guix now requires the avahi service type
          (service avahi-service-type)

          (simple-service 'add-extra-hosts hosts-service-type
                          (list (host "127.0.0.1" "dobby"
                                      '("local.gnucode.me"
                                        "local.propernaming.org"))
                                (host "45.56.66.20" "locke-lamora"
                                      '("lamora" "locke"))))

          ;; this lets connman connect to encrypted wifi.
          ;; (service wpa-supplicant-service-type)
          
          ;; if you ever need to connect to wireless networks,
          ;; just use the command: cmst
          ;; there should also be a logo on the top of the sway status bar too.
          ;; (service connman-service-type
          ;; (connman-configuration
          ;; (disable-vpn? #t)
          ;; (iwd? #f)))
          
          ;; https://lists.gnu.org/archive/html/help-guix/2016-08/msg00061.html
          ;; https://help.ubuntu.com/community/Dovecot
          ;; https://help.ubuntu.com/community/DovecotLDAP
          (service dovecot-service-type
                   (dovecot-configuration (mail-location
                                           "maildir:~/.mail/dismail.de:LAYOUT=fs")
                                          (listen '("127.0.0.1"))
                                          ;; this will change a login of "joshua" to a login of "joshua@dismail.de"
                                          ;; (auth-default-realm "dismail.de")
                                          ;; I do not need ssl support in a locally running dovecot.  :)
                                          (ssl? "no")
                                          ;; I have find this useful if dovecot cannot find
                                          ;; my mail
                                          (mail-debug? #t)
                                          ;; currently the only way to login to dovecot is to use
                                          ;; joshua and my regular user password
                                          ;; joshua@dismail.de fails and
                                          ;; jbranso@dismial.de fails.
                                          (protocols (list (protocol-configuration
                                                            (name "imap")
                                                            (mail-max-userip-connections
                                                             1))))
                                          (services (list (service-configuration
                                                           (kind "imap")
                                                           (client-limit 1))))))
          (service greetd-service-type
                   (greetd-configuration (greeter-supplementary-groups (list
                                                                        "video"
                                                                        "input"
                                                                        "seat"))
                                         (terminals (list (greetd-terminal-configuration
                                                           (terminal-vt "1")
                                                           (terminal-switch #t))
                                                          (greetd-terminal-configuration
                                                           (terminal-vt "2")
                                                           (terminal-switch #t))
                                                          (greetd-terminal-configuration
                                                           (terminal-vt "3")
                                                           (terminal-switch #t))
                                                          (greetd-terminal-configuration
                                                           (terminal-vt "4")
                                                           (terminal-switch #t))
                                                          (greetd-terminal-configuration
                                                           (terminal-vt "5")
                                                           (terminal-switch #t))
                                                          (greetd-terminal-configuration
                                                           (terminal-vt "6")
                                                           (terminal-switch #t))))))

          (service mingetty-service-type
                   (mingetty-configuration (tty "tty8")))
          (service mingetty-service-type
                   (mingetty-configuration (tty "tty7")))
          ;; enable gpg
          ;;
          ;; GPG_TTY=$(tty)
          ;; export GPG_TTY
          ;; # start the gpg agent
          ;; gpgconf --kill gpg-agent  # (just in case it’s already running)
          ;; eval $(gpg-agent --daemon) # start the gpg-agent
          ;; (service gpg-agent-service-type)
          (service mcron-service-type
                   (mcron-configuration (jobs (list idutils-job updatedb-job
                                                    ;;mbsync-every-5-minutes
                                                    ))))

          ;; (service nftables-service-type
          ;; (nftables-configuration
          ;; (ruleset
          ;; (local-file (string-append %current-directory "nftables.conf")))))
          
          (service nginx-service-type
                   (nginx-configuration
                    (server-blocks
                     (list
                      (nginx-server-configuration
                       (server-name '("date.com"))
                       (listen '("date.com"))
                       (root
                           "/home/joshua/prog/guile/decent-dating/")
                       (locations (list
                                   (nginx-location-configuration
                                    (uri
                                     "/")
                                    (body '
                                     ("proxy_pass http://date.com:8082;")))
                                   (nginx-location-configuration
                                    (uri
                                     "/css/")
                                    (body '
                                     ("root /home/joshua/prog/guile/decent-dating/;")))
                                   (nginx-location-configuration
                                    (uri
                                     "/img/")
                                    (body '
                                     ("root /home/joshua/prog/guile/decent-dating/;"))))))
                      (nginx-server-configuration
                       (server-name '("local.gnucode.me"))
                       (listen '("local.gnucode.me"))
                       ;; (root "/home/joshua/prog/guile/gnucode.me/site/")
                       (root
                           "/srv/http/gnucode.me/site/")
                       (locations (list
                                   (nginx-location-configuration
                                    (uri
                                     "/form/")
                                    (body '
                                     ("proxy_pass http://local.gnucode.me:8081;")))
                                   (nginx-location-configuration
                                    (uri
                                     "/form/css/")
                                    (body '
                                     ("root /home/joshua/prog/guile/;"))))))
                      (nginx-server-configuration
                       (server-name '("local.the-nx.com"))
                       (listen '("local.the-nx.com"))
                       ;; (root "/home/joshua/prog/guile/gnucode.me/site/")
                       (root
                           "/srv/http/gnucode.me/site/")
                       (locations (list
                                   (nginx-location-configuration
                                    (uri
                                     "/")
                                    (body '
                                     ("proxy_pass http://local.the-nx.com:8080;"))))))
                      ;; (nginx-server-configuration
                      ;; (server-name '("local.propernaming.org"))
                      ;; (listen '("local.propernaming.org"))
                      ;; (root "/home/joshua/prog/guile/propernaming/site/")
                      ;; (locations
                      ;; (list
                      ;; (nginx-location-configuration
                      ;; (uri  "/css/")
                      ;; (body '("root /home/joshua/prog/guile/propernaming/site/;")))
                      ;; )))
                      ;; %nginx-servers
                      ))))

          ;; (openvpn-client-service
          ;; #:config
          ;; (openvpn-client-configuration
          ;; (ca "/home/joshua/prog/guile/guix-config/vpn/ca.crt")
          ;; ;;(cert "/home/joshua/prog/guile/guix-config/vpn/client.crt")
          ;; (key "/home/joshua/prog/guile/guix-config/vpn/client.key")
          ;; ;; the expressvpn file I use disables lzo compression
          ;; (comp-lzo? #f)
          ;; (auth-user-pass "/home/joshua/login.conf")
          ;; (remote
          ;; (list
          ;; (openvpn-remote-configuration
          ;; (name "213.232.87.77")
          ;; (port 1195))))))
          
          (service seatd-service-type)

          ;; make guix system autoupgrade itself once a week!
          ;; this is currently failing...see /var/log/unattended-upgrade.log
          ;; (service unattended-upgrade-service-type
          ;; (unattended-upgrade-configuration
          ;; (schedule "30 01 * * 0")
          ;; (system-expiration (* 3 30 24 3600))))
          
          ;; currently does not work so not enabling it.
          ;; (service wireguard-service-type
          ;; (wireguard-configuration
          ;; (private-key "/home/joshua/prog/gnu/guix/guix-config/wireguard-keys/laptop.private.key")
          ;; (peers
          ;; (list
          ;; (wireguard-peer
          ;; (name "my client laptop")
          ;; (endpoint "wireguard.gnucode.me:51820")
          ;; (public-key "9zhoGW8DYr9zJHFbzBZUSBQHWlY6h/9HeoNzrC58dTc=")
          ;; (allowed-ips '("0.0.0.0/0")))))))
          
          ;; Fedora is including a zram device by default
          (service zram-device-service-type
                   (zram-device-configuration (size "512M")))

          ;; The global fontconfig cache directory can sometimes contain
          ;; stale entries, possibly referencing fonts that have been GC'd,
          ;; so mount it read-only.
          ;; fontconfig-file-system-service
          
          (service ntp-service-type)
          ;; %desktop-services has both pulse and alsa services defined.
          (service pulseaudio-service-type
                   (pulseaudio-configuration (script-file (local-file (string-append
                                                                       %current-directory
                                                                       "/pulse/default.pa")))))
          (service alsa-service-type)

          %my-base-services))

  ;; I can read 'man 5 suoders' for tips about the syntax of suoders file.
  ;; the very end of the file has some examples.
  (sudoers-file (plain-file "sudoers"
                            (string-append (plain-file-content
                                            %sudoers-specification)
                             "Cmnd_Alias KILL = /run/current-system/profile/bin/kill\n"
                             "Cmnd_Alias SHUTDOWN = /run/current-system/profile/sbin/shutdown\n"
                             "Cmnd_Alias HALT = /run/current-system/profile/sbin/halt\n"
                             "Cmnd_Alias REBOOT = /run/current-system/profile/sbin/reboot\n"
                             "Cmnd_Alias HERD = /run/current-system/profile/bin/HERD\n"
                             "joshua ALL = KILL, SHUTDOWN, HALT, REBOOT, HERD \n")))
  ;; ;; Here the user joshua may run basic maintence tasks such as
  ;; starting/stoping services, rebooting, wifi, etc.
  )
